package algorithm;

import problem.Problem;
import solution.Solution;

public abstract class SimWWOAlgorithm<T extends Number, T2 extends Number, S extends Solution<T,T2>, Tuple>
		extends Algorithm<T, T2, S, Tuple> {

	/* 水波算法独有的参数 */
	double alpha;// 波长衰减系数
	double beta;// 碎浪系数
	double betaMax;
	double betaMin;
	int kmax;// 用于碎浪过程中，选择的维度数量
	double lambda;// 为每个波设置的初始波长
	double epsilon = 0.000001;// 防止0除
	int popSizeMax;// 最大种群
	int popSizeMin;// 最小种群

	public SimWWOAlgorithm(Problem<T, Tuple, T2> problem, boolean isMax, String algName, int NFE, double alpha,
			double betaMax, double betaMin, int kmax, double lambda, int popSizeMax, int popSizeMin) {
		// 初始种群为popSizeMax
		super(problem, isMax, algName, popSizeMax, NFE);
		this.alpha = alpha;
		this.betaMax = betaMax;
		this.betaMin = betaMin;
		this.beta = betaMax;
		this.kmax = kmax;
		this.lambda = lambda;
		this.popSizeMax = popSizeMax;
		this.popSizeMin = popSizeMin;
	}

	/** 水波算法独有的操作 **/
	/**
	 * 传播操作
	 */
	public abstract S propagate(S wave);

	/**
	 * 碎浪操作
	 */
	public abstract S breaking(S wave);

	/**
	 * 更新参数
	 */
	@Override
	public void updateParameters() {
		// 更新beta
		beta = betaMax - (betaMax - betaMin) * (current_NFE * 1.0 / NFE);
		// 更新population
		int prePopSize = popSize;// 之前的种群大小
		popSize = (int) Math.round(popSizeMax - (popSizeMax - popSizeMin) * (current_NFE * 1.0 / NFE));
		// 从种群中移除(prePopSize-popSize)个数的水波
		deleteWorstWaves(prePopSize, popSize);
	}

	// 删除(prePopSize-popSize)个数的最差水波
	private void deleteWorstWaves(int prePopSize, int popSize) {
		if (prePopSize == popSize)
			return;
		int difference = prePopSize - popSize;
		for (int i = 1; i <= difference; i++) {
			S worst = population.get(0);
			for (int j = 1; j < population.size(); j++) {
				if ((Double) worst.getValue() < (Double) population.get(j).getValue()) {
					worst = population.get(j);
				}
			}
			population.remove(worst);
		}

		// 重新生成worst
		S worst = population.get(0);
		for (int j = 1; j < population.size(); j++) {
			if ((Double) worst.getValue() < (Double) population.get(j).getValue()) {
				worst = population.get(j);
			}
		}
	}

}
